<?php 

	class Joob_Utils_Validator{
	
		/**
		 * @desc Check if the input data is empty or not.
		 * @param mixed $obj
		 * @return true/false
		 */
		public static function isEmpty(&$obj){
			if ($obj===0) return false; # 0 is not empty.
			if ($obj==="" || $obj==null) return true; # "" and null are empty
			if (empty($obj)) return true;
			return false;
		}
		
		
		
		/**
		 * @desc Inverse version of isEmpty
		 * @param Mixed $obj
		 */
		public static function notEmpty(&$obj){
			if (self::isEmpty($obj)){
				return false;
			}
			return true;
		}
		
        
		/**
		 * @desc Extend version of str_replace.
		 * Here we want to ensure that the array length is the same in
		 * search and replace.
		 */
		public static function replace($source,$search,$replace){
			if (count($search)!=count($replace)){
				fatal("validate/replace");
			}
			return str_replace($search,$replace,$source);
		}
		
		

		/**
		 * @desc Validate pattern. Check if all character of $str is in $pattern. So, 
		 * V::pattern('123456','123')=true but V:pattern('123456','12ab')=false. 
		 */
		public static function pattern(&$str,$pattern){
			for ($i=0; $i<strlen($str); $i++)
			{
				$c=$str{$i};
				$pos=strpos($pattern,$c);
				if ($pos===false) return false;
			}
			return true;
		}
		
		
        
        /**
         * @desc Validate pattern. Verify that no charactor of $pattern is in $str 
         */ 
        public static function nopattern(&$str,$pattern){
            for ($i=0; $i<strlen($str); $i++){
                $c=$str{$i};
                $pos=strpos($pattern,$c);
                if ($pos!==false) return false;
            }
            return true;
        }
        
		
        /**
        * Function: is_int()
        * ---------------------------------------
        * @uses Validate that the input is an integer.
        * @param mixed $a
        * @param int $max
        * @param int $min
        */
		public static function is_int(&$a, $max=0, $min=0)
		{
			if (!is_numeric($a)) return false;
			if ($a!=floor($a)) return false;
			if ($max>0 && $a>$max){
				return false;
			}
			if ($min>0 && $a<$min){
				return false;
			}
			return true;
		}
        
        
        
        /** 
        * @desc Validate that the input is an integer. Alias of is_int()
        * @param mixed $a
        * @param int $max
        * @param int $min
        */
        public static function isInt(&$a, $max=0, $min=0){
            return self::is_int($a, $max, $min);
        }
		
        
        
        /**
         * @desc Ensure that the string doesn't contain any dangerous charactor.
         * @param $str The string to be tested.
         */
		public static function safeChar(&$str){
			return self::nopattern($str, "#$%^&*('\":;{|}[]+=~`,?><\\");
		}
		
        
		/**
		 * 
		 * @desc Check if the $str is a valid string within a good
		 * range.
		 * @param string $str
		 * @param int $max_length The max allowed length. 0 for infinity.
		 * @param int $min_length The min allowed length. 0 as default.
		 */
		public static function isString(&$str,$max_length=0,$min_length=0){
			self::basicFilter($str);
			if (!self::length($str,$min_length,$max_length)) return false;
			return self::pattern($str,"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 !@$%^&*_-=+~,.?/;[]\\\n#");
		}
		
		
		/**
		 * Validate that the string contain only alpha numeric characters. The 
		 * space is allowed.
		 * @param string $str Ths string to be scanned.
		 * @param int $max_length The max allowed length. 0 for infinity.
		 * @param int $min_length The min allowed length. 0 as default.
		 */
		public static function alphaNum(&$str,$max_length=0,$min_length=0){
			self::basicFilter($str);
			
			if (!self::length($str,$min_length,$max_length)) return false;
			return self::pattern($str, 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 -,');
            return true;
		}

		
		/**
		 * Validate that the string contain only alpha numeric characters and 
		 * some additional safe charaters such as -,:;.
		 * @param string $str Ths string to be scanned.
		 * @param int $max_length The max allowed length. 0 for infinity.
		 * @param int $min_length The min allowed length. 0 as default.
		 */
		public static function alphaNumLoose(&$str,$max_length=0,$min_length=0){
			self::basicFilter($str);
			
			if (!self::length($str,$min_length,$max_length)) return false;
			return self::pattern($str, 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 -,:;');
		}
		
		
		/**
		 * Validate that the string contain only alpha numeric characters in strict mode.
		 * @param string $str Ths string to be scanned.
		 * @param string $max_length The max allowed length. 0 for infinity.
		 * @param string $min_length The min allowed length. 0 as default.
		 */
		public static function alphaNumStrict(&$str,$max_length=0,$min_length=0){
			self::basicFilter($str);
			
			if (!self::length($str,$min_length,$max_length)) return false;
			return self::pattern($str,'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 ');
		}
		
		
		/**
		 * 
		 * Validate that the string could be a name of data (such as 
		 * file name, variable name).
		 * @param string $str The string to be scanned.
		 * @param int $max_length The max allowed length. 0 for infinity.
		 * @param int $min_length The min allowed length. 0 as default.
		 */
		public static function alphaNumData(&$str,$max_length=0,$min_length=1){
			self::basicFilter($str);
			if (!self::length($str,$min_length,$max_length)) return false;
			return self::pattern($str,'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_');
		}
		
        

		
		# Function: length($str,$min,$max)
		# ----------------------------------------
		# Validate the length of the string.
		
		public static function length(&$str,$min=0,$max=0){
			self::basicFilter($str);		
			if ($min!=0 && strlen($str)<$min) return false;
			if ($max!=0 && strlen($str)>$max) return false;
			return true;
		}
		
		
		# Function: html()
		# ----------------------------------------
		# Validate if the string is safe html. Only allow the following tags: b, i, u, br.
		# Notice that after the data is pass, it actually changed.
		
		public static function html(&$str,$max_length=0,$min_length=0){
			self::deep_filter($str);
			if (!self::length($str,$min_length,$max_length)) return false;
			
			if (self::pattern($str,"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 !@$%^&*_-=+~,.?/;[]\\\n#")==false) return false;
			return true;
		}
		
		
		/**
		 * @desc Validate Email Address
		 * @param $email
		 */
		public static function email(&$email){
			self::basicFilter($email);
			$email=str_replace("&#64;",'@',$email);
			
			$a=Joob_Utils_Word::split("@",$email);
			if (count($a)!=2) return false;
			
			$pattern="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789._-";
			
			if (self::pattern($a[0],$pattern)==false) return false;
			if (self::pattern($a[1],$pattern)==false) return false;
			return true;
		}
		
		
		/**
		 * @desc Validator password. The password
		 * has to contain allowed charactor, with min length and max length
		 * to be defined as constant.
		 * @param String $pass
		 * @return true/false
		 */
		public static function password(&$pass){
			self::basicFilter($pass);
			if (self::length($pass,PW_MIN_LENGTH,PW_MAX_LENGTH)==false) return false;
			return self::alphaNumStrict($pass);
		}
		
		
		/**
		 * @desc Validate url address strictly. Only http://$address or $address are 
		 * allowed, where address is of the form $a1.$a2...$an
		 * @param String $url
		 * @return true/false
		 */
		public static function url(&$url){
			self::basicFilter($url);
			
			$a=Joob_Utils_Word::split("//",$url);
			if (count($a)!=1 && count($a)!=2) return false;
			
			$pattern="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789#&~._-?";
			
			if (count($a)==1){
				$web=$a[0];
				$b=Joob_Utils_Word::split("/",$web);
				for ($i=0; $i<count($b); $i++)
				{
					if (self::pattern($b[$i],$pattern)==false) return false;
				}
				return true;
			}
			else{
				$uri=$a[0];
				if (Joob_Utils_Word::icmp($uri,'http:')==false && Joob_Utils_Word::icmp($uri,'https:')==false) return false;
				
				$web=$a[1];
				$b=Joob_Utils_Word::split("/",$web);
				for ($i=0; $i<count($b); $i++)
				{
					if (self::pattern($b[$i],$pattern)==false) return false;
				}
				return true;
			}
		}
		

		/**
		 * @desc Verify URL is of valid format
		 * @param String $str
		 */
		public static function filename(&$str){
			self::basicFilter($str);
			
			if (strlen($str)<1) return false;
			if (strpos($str,'..')!==false) return false;
			
			return self::pattern($str, 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._');
		}
		
		
		# Function: folder()
		# ---------------------------------------
		# Validate a string that is a valid file folder (no .. is allowed)
		
		public static function folder(&$str){
			self::basicFilter($str);
			
			if (strlen($str)<1) return false;
			
			$r=Joob_Utils_Word::split('/',$str);
			if (count($r)<=0) return false;
			
			for ($i=0; $i<count($r); $i++)
			{
				if (!self::pattern($r[$i], 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.'))
				{
					return false;
				}
				if (strpos($str,'..')!==false) return false;
			}
			
			$data=$r[0];
			for ($i=1; $i<count($r); $i++)
			{
				$data=$data."/".$r[$i];
			}
			if ($str!=$data) return false;
			return true;
		}
        
        
        
        # Function: filter(&$str)
        # --------------------------------------
        # Pass by reference. Return new string where unnecessary blocks are removed.
        
        protected static function basicFilter(&$str)
        {
            $str=trim($str);
        }
        
        
        # Function: filter(&$str)
        # --------------------------------------
        # Pass by reference. Return new string where unnecessary blocks are removed.
        
        protected static function filter(&$str)
        {
            $str=trim($str);
        }
        
        
        # Function: deep_filter(&$str)
        # ---------------------------------------
        # Deeply filtering the string. Replace some safe html tags.
        
        protected static function deepFilter(&$str)
        {
            self::basicFilter($str);
            
            $search=array('"', "'", '<', '>', ':', '(', ')');
            $replace=array('&quot;', '&#39;', '&lt;', '&gt;', '&#58;', '&#40;', '&#41;');
            
            $s=self::replace($str,$search,$replace);
            $str=$s;
        }
	}
?>